﻿using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Drawing;
using System.Drawing.Drawing2D;
using System.IO;
using System.Linq;
using System.Runtime.InteropServices;
using System.Threading;
using System.Threading.Tasks;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using DevExpress.Data;
using DevExpress.Xpf.Bars;
using DevExpress.Xpf.Core;
using DevExpress.Xpf.Core.Native;
using DevExpress.Xpf.Editors;
using DevExpress.Xpf.RichEdit.Controls.Internal;
using DevExpress.XtraRichEdit;
using DevExpress.XtraRichEdit.API.Layout;
using DevExpress.XtraRichEdit.API.Native;
using DevExpress.XtraRichEdit.API.Native.Implementation;
using DevExpress.XtraRichEdit.Commands;
using DGIS.Word.WPF.ICommand;
using DGIS.Word.WPF.Model;
using Color = System.Windows.Media.Color;
using Pen = System.Drawing.Pen;
using Point = System.Drawing.Point;

namespace DGIS.Word.WPF
{
    /// <summary>
    /// MainWindow.xaml 的交互逻辑
    /// </summary>
    public partial class MainWindow : Window
    {

        private int zIndex = 0;
        private int lineWidth = 4;
        private Color lineColor = Colors.Red;
        private bool enableEraser = false;

        public MainWindow()
        {
            InitializeComponent();
        }

        #region 事件

        private void Window_Loaded(object sender, RoutedEventArgs e)
        {
            Init();
        }


        /// <summary>
        /// 文本输入,加载输入法
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void richEditControl1_MouseUp(object sender, MouseButtonEventArgs e)
        {
            ShowInputPanel();
        }

        /// <summary>
        /// 文本离开,取消输入法
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void RichEditControl1_OnMouseLeave(object sender, MouseEventArgs e)
        {
            //HideInputPanel();
        }


        /// <summary>
        /// 鼠标移动事件(擦除状态下，移除元素)
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void richEditControl1_MouseMove(object sender, MouseEventArgs e)
        {
            if(!enableEraser)
                return;

            System.Windows.Point winPoint = e.GetPosition(this.richEditControl1);
            System.Drawing.Point point = new System.Drawing.Point((int)winPoint.X, (int)winPoint.Y);
            HitTestSearchOption searchOption = HitTestSearchOption.Exact;

            DevExpress.XtraRichEdit.PageLayoutPosition pageLayoutPosition = this.richEditControl1.ActiveView.GetDocumentLayoutPosition(point);
            if (pageLayoutPosition == null)
            {
                return;
            }
            else
            {
                int pageIndex = pageLayoutPosition.PageIndex;
                point = pageLayoutPosition.Position;
                HitTestManager hitTest = new HitTestManager(this.richEditControl1.DocumentLayout);
                LayoutPage layoutPage = this.richEditControl1.DocumentLayout.GetPage(pageIndex);
                RichEditHitTestResult result = hitTest.HitTest(layoutPage, point, searchOption);
                if (result.LayoutElement.Type == LayoutType.FloatingPicture)
                {
                    LayoutFloatingObject obj = result.LayoutElement as LayoutFloatingObject;
                    DelStroke(obj.GetDocumentShape());
                }
            }
        }

        /// <summary>
        /// 选色
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void PenColorEdit_ColorChanged(object sender, RoutedEventArgs e)
        {
            lineColor = this.penColorEdit.Color;
            this.penColor.EditValue = lineColor;
            this.mainCanvas.DefaultDrawingAttributes.Color = lineColor;
        }

        /// <summary>
        /// 线宽
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void PenLineEdit_SelectedIndexChanged(object sender, RoutedEventArgs e)
        {
            lineWidth = int.Parse(this.penLineEdit.EditValue.ToString());
            this.penLine.EditValue = lineWidth;
            this.penLine.PopupControl.ClosePopup();

            this.mainCanvas.DefaultDrawingAttributes.Width = lineWidth;
            this.mainCanvas.DefaultDrawingAttributes.Height = lineWidth;
        }


        #endregion

        #region 方法

        /// <summary>
        /// 初始化
        /// </summary>
        private void Init()
        {
            if (App.Dic.ContainsKey("SplashWindow"))
            {
                SplashScreenView sw = App.Dic["SplashWindow"] as SplashScreenView;
                sw.Dispatcher.Invoke((Action)(() => sw.Close()));//在sw的线程上关闭SplashWindow
            }

            if (Application.Current.Properties["param"] != null)
            {
                string docPath = Application.Current.Properties["param"].ToString();
                try
                {
                    this.richEditControl1.LoadDocument(docPath);
                }
                catch (Exception ex)
                {
                    MessageBox.Show(docPath+" 打开失败", "提示", MessageBoxButton.OK, MessageBoxImage.Error);
                    Environment.Exit(0);
                }

            }

            this.Closed += (s, e) =>
            {
                this.richEditControl1.Dispose();
            };
            this.closeImgBtn.MouseDown += (s, e) =>
            {
                this.Close();
            };


            //重写保存按钮事件
            biFileSave.Glyph = ChangeBitmapToImageSource(Resource.save);
            biFileSave.Command = new SaveCommand();
            biFileSave.CommandParameter = this.richEditControl1;
            biFileSave.Content = "另存为";
            biFileSave.IsEnabled = true;

            //重写开始画笔事件
            this.startPenItem.Command = new StartPenCommand();
            this.startPenItem.CommandParameter = this;

            //重写停止画笔事件
            this.endPenItem.Command = new EndPenCommand();
            this.endPenItem.CommandParameter = this;

            //重写擦除事件
            this.eraserItem.Command=new EraserCommand();
            this.eraserItem.CommandParameter = this;

            //重写画笔线宽选择事件
            this.penLine.ItemClick+= (e, s) =>
            {
                //try
                //{
                //  this.cccc.ShowPopup(this.penLineEdit);
                //}
                //catch (Exception ex)
                //{
                    
                //}
            };
            this.penLineEdit.SelectedIndexChanged += PenLineEdit_SelectedIndexChanged;

            //重写画笔颜色选择事件
            this.penColor.ItemClick += (e, s) =>
            {
                //try
                //{
                //    this.penColor.PopupControl.ShowPopup(this.penColorEdit);
                //}
                //catch (Exception ex)
                //{
                    
                //}
            };
            this.penColorEdit.ColorChanged += PenColorEdit_ColorChanged;


            //画笔绘制事件
            this.mainCanvas.StrokeCollected += (s, o) =>
            {
                Stroke item = new Stroke()
                {
                    Color = lineColor,
                    LineWidth = lineWidth,
                    Points = new List<float[]>()
                };

                System.Windows.Ink.Stroke stroke = mainCanvas.Strokes[0];

                for (int i = 0; i < stroke.Clone().StylusPoints.Count; i++)
                {
                    var pt = stroke.StylusPoints[i];
                    item.Points.Add(new float[2] { (float)pt.X, (float)pt.Y });
                }
                mainCanvas.Strokes.Clear();

                DrawStroke(item);
            };

            Task.Factory.StartNew(() =>
            {
                Thread.Sleep(5000);
                this.Dispatcher.Invoke(new Action(() =>
                {
                    this.Topmost = false;
                }));
            }).ContinueWith((o) =>
            {
                o.Dispose();
            });

        }


        /// <summary>
        /// 开始画笔
        /// </summary>
        /// <param name="start"></param>
        public void StartPen(bool start)
        {
            this.richEditControl1.ActiveView.ZoomFactor = 1;

            startPenItem.IsEnabled = !start;
            endPenItem.IsEnabled = start;
            eraserItem.IsEnabled = !start;
            penColor.IsEnabled = start;
            penLine.IsEnabled = start;
            var cursor= new Cursor(new MemoryStream(Resource.MetroBusy));
            if (!start)
                this.mainCanvas.Cursor = cursor;

            this.mainCanvas.Visibility = start ? Visibility.Visible : Visibility.Hidden;
        }

        /// <summary>
        /// 擦除
        /// </summary>
        public void StartEraser()
        {
            Cursor cursor;
            
            enableEraser = !enableEraser;
            if (!enableEraser)
            {
                cursor = Cursors.Arrow;
                this.richEditControl1.ReadOnly = false;
                this.eraserItem.LargeGlyph = ChangeBitmapToImageSource(Resource.eraser);
                this.eraserItem.Content = "擦除";
                this.startPenItem.IsEnabled = true;
                
            }
            else
            {
                cursor = new Cursor(new MemoryStream(Resource.MetroBusy));
                this.richEditControl1.ReadOnly = true;
                this.eraserItem.LargeGlyph = ChangeBitmapToImageSource(Resource.eraser_red);
                this.eraserItem.Content = "停止擦除";
                this.startPenItem.IsEnabled = false;
            }

            var controls = GetTextboxControls(this.richEditControl1);
            foreach (FrameworkElement control in controls)
            {
                Console.WriteLine(control.GetType().FullName);
                control.Cursor = cursor;
            }
        }

        /// <summary>
        /// 绘制痕迹
        /// </summary>
        /// <param name="stroke"></param>
        private void DrawStroke(Stroke stroke)
        {
            if (stroke.Points.Count < 3)
                return;

            //获取左上右下坐标和画笔痕迹长宽
            float minX = float.MaxValue;
            float maxX = 0;
            float minY = float.MaxValue;
            float maxY = 0;

            float width = 0;
            float height = 0;

            for (int i = 0; i < stroke.Points.Count; i++)
            {
                var pt = stroke.Points[i];
                if (pt[0] < minX)
                    minX = pt[0];
                if (pt[0] > maxX)
                    maxX = pt[0];
                if (pt[1] < minY)
                    minY = pt[1];
                if (pt[1] > maxY)
                    maxY = pt[1];
            }

            width = maxX - minX;
            height = maxY - minY;

            //绘制画笔痕迹图片
            Bitmap bmp = new Bitmap((int)width + stroke.LineWidth+10, (int)height + stroke.LineWidth+10);
            Graphics g = Graphics.FromImage(bmp);
            g.SmoothingMode = SmoothingMode.HighQuality;

            Pen pen = new Pen(System.Drawing.Color.FromArgb(255, stroke.Color.R, stroke.Color.G, stroke.Color.B),
                stroke.LineWidth);

            System.Drawing.PointF[] points = new System.Drawing.PointF[stroke.Points.Count];
            for (int i = 0; i < stroke.Points.Count; i++)
            {
                var pt = stroke.Points[i];
                //var pt2 = stroke.Points[i + 1];

                var x1 = (float)(pt[0] - minX + stroke.LineWidth);
                var y1 = (float)(pt[1] - minY + stroke.LineWidth);
                //var x2 = (float)(pt2[0] - minX);
                //var y2 = (float)(pt2[1] - minY);

                //g.DrawLine(pen, x1, y1, x2, y2);

                points[i] = (new PointF(x1, y1));
            }

            g.DrawCurve(pen, points);

            //标注起点坐标
            var startPoint = this.mainCanvas.PointToScreen(new System.Windows.Point(minX, minY));
            //标注起点坐标相对于文本控件的位置
            var editPoint = this.richEditControl1.PointFromScreen(startPoint);

            //总页码
            int pageCount = ((DevExpress.XtraRichEdit.PageBasedRichEditView)richEditControl1.ActiveView).PageCount;

            ////是否有分页符
            //bool hasPageBlock = false;
            //for (int i = 0; i < pageCount; i++)
            //{
            //    LayoutPage layoutPage = this.richEditControl1.DocumentLayout.GetPage(i);
            //    if (!hasPageBlock)
            //    {
            //        hasPageBlock = layoutPage.PageAreas.FirstOrDefault().Columns.Any(x => x.Rows.Any(y => y.Boxes.Any(z => z.Type == LayoutType.PageBreakBox)));
            //        break;
            //    }
            //}

            //获取当前可见页
            var pageInfos = richEditControl1.ActiveView.GetVisiblePageLayoutInfos();
            foreach (PageLayoutInfo pageInfo in pageInfos)
            {
                if (pageInfo.Bounds.Y > (-1) * pageInfo.Bounds.Height)
                {

                    //画笔起点是否在当前可见页
                    if (editPoint.X >= pageInfo.Bounds.X && editPoint.X <= pageInfo.Bounds.X + pageInfo.Bounds.Width &&
                        editPoint.Y >= pageInfo.Bounds.Y && editPoint.Y <= pageInfo.Bounds.Y + pageInfo.Bounds.Height)
                    {

                        //当前可见页
                        int pageIndex = pageInfo.PageIndex;
                        LayoutPage layoutPage = this.richEditControl1.DocumentLayout.GetPage(pageIndex);

                        //在画笔所在页创建焦点
                        DocumentPosition documentPosition;
                        if (layoutPage.MainContentRange.Length == 1 && pageIndex == pageCount - 1)
                        {
                            //最后一页，且是分页符空白页
                            documentPosition =
                                  this.richEditControl1.Document.CreatePosition(
                                      layoutPage.MainContentRange.Start + 1);
                            DocumentRange documentRange =
                                this.richEditControl1.Document.CreateRange(documentPosition, 1);
                            this.richEditControl1.Document.InsertDocumentContent(documentPosition, documentRange);
                            documentPosition = documentRange.End;

                            this.richEditControl1.Document.Delete(documentRange);
                        }
                        else
                        {
                            documentPosition =
                                this.richEditControl1.Document.CreatePosition(layoutPage.MainContentRange.Start +
                                                                              layoutPage.MainContentRange.Length / 2);
                        }

                        //if (layoutPage.PageAreas.FirstOrDefault().Columns.Any(x => x.Rows.Any(y => y.Boxes.Any(z => z.Type == LayoutType.PageBreakBox))))
                        //if (this.richEditControl1.Document.HtmlText.Contains("cs1B16EEB5"))

                        /*if (hasPageBlock)
                        {
                            //有分页符
                            

                            if (pageIndex >0)
                            {
                                LayoutPage preLayoutPage = this.richEditControl1.DocumentLayout.GetPage(pageIndex - 1);
                                if (
                                    !preLayoutPage.PageAreas.FirstOrDefault().Columns.Any(x =>x.Rows.Any(y => y.Boxes.Any(z => z.Type == LayoutType.PageBreakBox))))
                                {
                                    //前一页没有分页符
                                    documentPosition =
                                         this.richEditControl1.Document.CreatePosition(layoutPage.MainContentRange.Start);
                                }
                                else
                                {
                                    //前一页有分页符
                                    documentPosition =
                                   this.richEditControl1.Document.CreatePosition(
                                       layoutPage.MainContentRange.Start);
                                    DocumentRange documentRange =
                                        this.richEditControl1.Document.CreateRange(documentPosition, 1);
                                    this.richEditControl1.Document.InsertDocumentContent(documentPosition, documentRange);
                                    documentPosition = documentRange.End;

                                    this.richEditControl1.Document.Delete(documentRange); 
                                }
                            }
                            else
                            {
                                documentPosition =
                                    this.richEditControl1.Document.CreatePosition(layoutPage.MainContentRange.Start);
                            }

                            //if (pageIndex == pageCount - 1)
                            //{
                            //    //if (!layoutPage.PageAreas.FirstOrDefault().Columns.Any(x => x.Rows.Any(y => y.Boxes.Any(z=>z.Type == LayoutType.ParagraphMarkBox))))
                            //    //{
                            //    //    DocumentRange documentRange = this.richEditControl1.Document.CreateRange(documentPosition, 1);
                            //    //    this.richEditControl1.Document.InsertDocumentContent(documentPosition, documentRange);
                            //    //    documentPosition = documentRange.End;

                            //    //    this.richEditControl1.Document.Delete(documentRange);
                            //    //}
                            //    documentPosition =
                            //        this.richEditControl1.Document.CreatePosition(layoutPage.MainContentRange.Start +
                            //                                                      layoutPage.MainContentRange.Length);
                            //    DocumentRange documentRange =
                            //        this.richEditControl1.Document.CreateRange(documentPosition, 1);
                            //    this.richEditControl1.Document.InsertDocumentContent(documentPosition, documentRange);
                            //    documentPosition = documentRange.End;

                            //    this.richEditControl1.Document.Delete(documentRange);
                            //}
                            //else
                            //{
                            //    documentPosition = this.richEditControl1.Document.CreatePosition(layoutPage.MainContentRange.Start);
                            //}
                        }
                        else
                        {
                            //无分页符
                            documentPosition = this.richEditControl1.Document.CreatePosition(layoutPage.MainContentRange.Start);

                            
                        }*/

                        var focusControl = richEditControl1.FocusElement;
                        var controls = GetCanvasControls(focusControl);

                        //根据相对位置坐标绘制图片
                        foreach (FrameworkElement box in controls)
                        {
                            Console.WriteLine(box.Name);
                            if (box.Name == "SuperRoot")
                            {
                                if (box.ActualHeight == 0)
                                {

                                }
                                else
                                {
                                    Canvas canva = box as Canvas;
                                    var point = box.GetPosition(this.richEditControl1);
                                    if (point.Y > (-1) * canva.ActualHeight && point.Y < canva.ActualHeight)
                                    {
                                        try
                                        {
                                            System.Windows.Point gridPoint = canva.PointFromScreen(startPoint);

                                            if (gridPoint.Y < canva.ActualHeight && gridPoint.Y > 0 &&
                                                gridPoint.X < canva.ActualWidth && gridPoint.X > 0)
                                            {
                                                Shape shape =
                                                    this.richEditControl1.Document.InsertPicture(documentPosition, bmp);
                                                shape.TextWrapping = TextWrappingType.InFrontOfText;
                                                shape.HorizontalAlignment = ShapeHorizontalAlignment.None;

                                                //shape.RelativeHorizontalPosition = ShapeRelativeHorizontalPosition.Column;
                                                //shape.RelativeVerticalPosition = ShapeRelativeVerticalPosition.Paragraph;
                                                shape.ZOrder = zIndex;
                                                zIndex++;

                                                shape.Name = "penLink";

                                                shape.Offset = new PointF((float)((gridPoint.X - stroke.LineWidth) * 3.12),
                                                    (float)((gridPoint.Y - stroke.LineWidth) * 3.12));



                                                break;
                                            }
                                        }
                                        catch (Exception ex)
                                        {

                                        }
                                    }


                                }
                            }
                        }
                        break;
                    }
                }
            }
        }

        /// <summary>
        /// 擦除
        /// </summary>
        /// <param name="shape"></param>
        private void DelStroke(Shape shape)
        {
            if (shape.Name == "penLink")
                this.richEditControl1.Document.Delete(shape.Range);
        }


        /// <summary>
        /// 私有方法，暴力获取编辑器内容控件
        /// </summary>
        /// <param name="control"></param>
        /// <returns></returns>
        private List<FrameworkElement> GetCanvasControls(FrameworkElement control)
        {
            List<FrameworkElement> items = new List<FrameworkElement>();

            int count = VisualTreeHelper.GetChildrenCount(control);
            for (int i = 0; i < count; i++)
            {
                var child = VisualTreeHelper.GetChild(control, i) as FrameworkElement;
                if (child != null)
                {
                    if (child is Canvas)
                        items.Add(child);

                    var cc = GetCanvasControls(child);
                    items.AddRange(cc);
                }
            }

            return items;
        }

        /// <summary>
        /// 获取文本框
        /// </summary>
        /// <param name="control"></param>
        /// <returns></returns>
        private List<FrameworkElement> GetTextboxControls(FrameworkElement control)
        {
            List<FrameworkElement> items = new List<FrameworkElement>();

            int count = VisualTreeHelper.GetChildrenCount(control);
            for (int i = 0; i < count; i++)
            {
                var child = VisualTreeHelper.GetChild(control, i) as FrameworkElement;
                if (child != null)
                {
                    if (child is RichEditViewPage)
                        items.Add(child);

                    var cc = GetTextboxControls(child);
                    items.AddRange(cc);
                }
            }

            return items;
        }

        /// <summary>
        /// 资源图片转换为WPF图片
        /// </summary>
        /// <param name="bitmap"></param>
        /// <returns></returns>
        public ImageSource ChangeBitmapToImageSource(Bitmap bitmap)

        {

            //Bitmap bitmap = icon.ToBitmap();

            IntPtr hBitmap = bitmap.GetHbitmap();


            ImageSource wpfBitmap = System.Windows.Interop.Imaging.CreateBitmapSourceFromHBitmap(

                hBitmap,

                IntPtr.Zero,

                Int32Rect.Empty,

                BitmapSizeOptions.FromEmptyOptions());




            return wpfBitmap;


        }

        #region 屏幕键盘

        private const Int32 WM_SYSCOMMAND = 274;
        private const UInt32 SC_CLOSE = 61536;
        [DllImport("user32.dll", SetLastError = true, CharSet = CharSet.Auto)]
        private static extern bool PostMessage(IntPtr hWnd, int Msg, int wParam, int lParam);
        [DllImport("user32.dll", SetLastError = true, CharSet = CharSet.Auto)]
        private static extern bool PostMessage(IntPtr hWnd, int Msg, uint wParam, uint lParam);
        [DllImport("user32.dll", SetLastError = true, CharSet = CharSet.Auto)]
        private static extern bool PostMessage(IntPtr hWnd, uint Msg, IntPtr wParam, IntPtr lParam);
        [DllImport("user32.dll", SetLastError = true, CharSet = CharSet.Auto)]
        private static extern IntPtr FindWindow(string lpClassName, string lpWindowName);
        [DllImport("user32.dll", CharSet = CharSet.Auto, SetLastError = true)]
        private static extern int RegisterWindowMessage(string lpString);

        /// <summary>
        /// 显示屏幕键盘
        /// </summary>
        /// <returns></returns>
        private bool ShowInputPanel()
        {
            try
            {
                dynamic file = "C:\\Program Files\\Common Files\\microsoft shared\\ink\\TabTip.exe";
                if (!System.IO.File.Exists(file))
                    return false;
                Process.Start(file);
                return true;
            }
            catch (Exception ex)
            {
                return false;
            }
        }

        /// <summary>
        /// 隐藏屏幕键盘
        /// </summary>
        private void HideInputPanel()
        {
            IntPtr TouchhWnd = new IntPtr(0);
            TouchhWnd = FindWindow("IPTip_Main_Window", null);
            if (TouchhWnd == IntPtr.Zero)
                return;
            PostMessage(TouchhWnd, WM_SYSCOMMAND, SC_CLOSE, 0);
        }

        #endregion

        #endregion
        
    }
}
